package com.jtny.nytb.equipment.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.toolkit.SqlHelper;
import com.jtny.component.core.util.PageUtils;
import com.jtny.component.entity.PageData;
import com.jtny.component.entity.PageParam;
import com.jtny.component.exception.ServiceException;
import com.jtny.component.util.Assert;
import com.jtny.component.util.BeanUtils;
import com.jtny.nytb.equipment.dao.dataparam.DataParamTempDAO;
import com.jtny.nytb.equipment.dao.rule.*;
import com.jtny.nytb.equipment.domain.dataparam.DataParamTempDO;
import com.jtny.nytb.equipment.domain.rule.*;
import com.jtny.nytb.equipment.dto.dataparam.DataParamTempDTO;
import com.jtny.nytb.equipment.dto.rule.*;
import com.jtny.nytb.equipment.enums.CodeRuleTypeEnum;
import com.jtny.nytb.equipment.service.CodeRuleService;
import com.jtny.nytb.equipment.utils.StrUtils;
import com.jtny.nytb.equipment.vo.dataparam.DataParamTempVO;
import com.jtny.nytb.equipment.vo.rule.CodeRuleDictQueryVO;
import lombok.AllArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.rmi.ServerException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 设备编号规则Service接口实现
 *
 * @author 智慧能源中心 - 伍天宇
 * @package com.jtny.energymonitor.equipment.service.impl
 * @fileName RuleNumberServiceImpl.java
 * @createTime 2023年09月14日 11:16
 * @Copyright© 2023 jtny
 * 江投能源技术研究院 版权所有
 */
@Service
@AllArgsConstructor
public class CodeRuleServiceImpl implements CodeRuleService {
    private DataParamTempDAO dataParamTempDAO;

    private CodeRuleDAO codeRuleDAO;
    private CodeLevelDAO codeLevelDAO;
    private CodeRulePreconditionDAO codeRulePreconditionDAO;
    private CodeRuleDictDAO codeRuleDictDAO;
    private CodeRuleSerialNumberDAO codeRuleSerialNumberDAO;

    private MeterCodeRuleDAO meterCodeRuleDAO;
    private MeterCodeRulePreconditionDAO meterCodeRulePreconditionDAO;
    private MeterCodeRuleDictDAO meterCodeRuleDictDAO;
    private MeterCodeRuleSerialNumberDAO meterCodeRuleSerialNumberDAO;
    private MeterCodeLevelDAO meterCodeLevelDAO;


    /**
     * 检查字典值
     *
     * @param type         类型
     * @param validDictDTO 有效字典 DTO
     * @return {@link ValidDictDTO}
     */
    @Override
    public ValidDictDTO checkDictValue(String type, ValidDictDTO validDictDTO) {
        List<CodeRuleDictDTO> codeRuleDictList = listRuleDictSelect(type, new CodeRuleDictSelectQueryDTO(validDictDTO.getLevelId(), null));
        if (CollUtil.isEmpty(codeRuleDictList)) {
            return validDictDTO;
        }
        for (CodeRuleDictDTO codeRuleDictDTO : codeRuleDictList) {
            if (StrUtil.equals(codeRuleDictDTO.getValue(), validDictDTO.getValue())) {
                validDictDTO.setDescription(codeRuleDictDTO.getDescription());
                return validDictDTO;
            }
        }
        return validDictDTO;
    }

    /**
     * 保存 设备编号规则
     *
     * @param codeRuleRequestDTO 设备编号规则请求DTO对象
     * @return {@link Boolean}
     */
    @Override
    @Transactional(rollbackFor = ServerException.class)
    public Boolean save(String type, CodeRuleRequestDTO codeRuleRequestDTO) throws ServiceException {
        Assert.notNull(type, "类型不能为空");

        if (CodeRuleTypeEnum.GENERAL.checkType(type)) {
            return saveGeneral(codeRuleRequestDTO);
        } else {
            return saveMeter(codeRuleRequestDTO);
        }
    }

    private Boolean saveGeneral(CodeRuleRequestDTO codeRuleRequestDTO) {
        CodeRuleDO toSave = BeanUtils.copyToObject(codeRuleRequestDTO, CodeRuleDO.class);
        boolean result = SqlHelper.retBool(codeRuleDAO.insert(toSave));
        if (result) {
            Long ruleId = toSave.getId();
            // 保存设备编号规则前置条件
            saveCodeRulePreconditionList(codeRuleRequestDTO.getCodeRulePreconditionList(), ruleId, codeRuleRequestDTO.getLevelId());
            // 保存设备编号规则字典
            saveCodeRuleDictList(codeRuleRequestDTO.getCodeRuleDictList(), ruleId);
            // 保存设备编号规则数据参量
            saveDataParamTempList(codeRuleRequestDTO.getDataParamTempList(), ruleId, 1);
        }
        return result;
    }

    private Boolean saveMeter(CodeRuleRequestDTO codeRuleRequestDTO) {
        MeterCodeRuleDO toSave = BeanUtils.copyToObject(codeRuleRequestDTO, MeterCodeRuleDO.class);
        boolean result = SqlHelper.retBool(meterCodeRuleDAO.insert(toSave));
        if (result) {
            Long ruleId = toSave.getId();
            // 保存设备编号规则前置条件
            saveMeterCodeRulePreconditionList(codeRuleRequestDTO.getCodeRulePreconditionList(), ruleId, codeRuleRequestDTO.getLevelId());
            // 保存设备编号规则字典
            saveMeterCodeRuleDictList(codeRuleRequestDTO.getCodeRuleDictList(), ruleId);
            // 保存设备编号规则数据参量
            saveDataParamTempList(codeRuleRequestDTO.getDataParamTempList(), ruleId, 3);
        }
        return result;
    }

    /**
     * 更新 设备编号规则
     *
     * @param codeRuleRequestDTO 设备编号规则请求DTO对象
     * @return {@link Boolean}
     */
    @Override
    @Transactional(rollbackFor = ServerException.class)
    public Boolean update(String type, CodeRuleRequestDTO codeRuleRequestDTO) throws ServiceException {
        Assert.notNull(type, "类型不能为空");

        if (CodeRuleTypeEnum.GENERAL.checkType(type)) {
            return updateGeneral(codeRuleRequestDTO);
        } else {
            return updateMeter(codeRuleRequestDTO);
        }
    }

    private Boolean updateMeter(CodeRuleRequestDTO codeRuleRequestDTO) {
        // 更新设备编号规则
        MeterCodeRuleDO toUpdate = BeanUtils.copyToObject(codeRuleRequestDTO, MeterCodeRuleDO.class);
        boolean result = SqlHelper.retBool(meterCodeRuleDAO.updateById(toUpdate));
        if (result) {
            Long ruleId = toUpdate.getId();
            // 保存设备编号规则前置条件
            saveMeterCodeRulePreconditionList(codeRuleRequestDTO.getCodeRulePreconditionList(), ruleId, codeRuleRequestDTO.getLevelId());
            // 保存设备编号规则字典
            saveMeterCodeRuleDictList(codeRuleRequestDTO.getCodeRuleDictList(), ruleId);
            // 保存设备编号规则数据参量
            saveDataParamTempList(codeRuleRequestDTO.getDataParamTempList(), ruleId, 3);
        }
        return result;
    }

    private Boolean updateGeneral(CodeRuleRequestDTO codeRuleRequestDTO) {
        // 更新设备编号规则
        CodeRuleDO toUpdate = BeanUtils.copyToObject(codeRuleRequestDTO, CodeRuleDO.class);
        boolean result = SqlHelper.retBool(codeRuleDAO.updateById(toUpdate));
        if (result) {
            Long ruleId = toUpdate.getId();
            // 保存设备编号规则前置条件
            saveCodeRulePreconditionList(codeRuleRequestDTO.getCodeRulePreconditionList(), ruleId, codeRuleRequestDTO.getLevelId());
            // 保存设备编号规则字典
            saveCodeRuleDictList(codeRuleRequestDTO.getCodeRuleDictList(), ruleId);
            // 保存设备编号规则数据参量
            saveDataParamTempList(codeRuleRequestDTO.getDataParamTempList(), ruleId, 1);
        }
        return result;
    }

    /**
     * 根据id查询 设备编号规则
     *
     * @param id 设备编号规则id
     * @return {@link CodeRuleResponseDTO}
     */
    @Override
    public CodeRuleResponseDTO getById(String type, Long id) throws ServiceException {
        Assert.notNull(type, "类型不能为空");

        if (CodeRuleTypeEnum.GENERAL.checkType(type)) {
            return getByIdGeneral(id);
        } else {
            return getByIdMeter(id);
        }

    }

    private CodeRuleResponseDTO getByIdMeter(Long id) {
        // 根据id查询 设备编号规则
        MeterCodeRuleDO codeRuleDO = meterCodeRuleDAO.selectById(id);
        // 根据规则id查询 设备编号规则数据参量
        List<DataParamTempDO> dataParamTempDOList = dataParamTempDAO.selectList(Wrappers.<DataParamTempDO>lambdaQuery()
                .eq(DataParamTempDO::getRelationType, 1)
                .eq(DataParamTempDO::getRelationId, id));
        // 根据规则id查询 设备编号规则前置条件
        List<MeterCodeRulePreconditionDO> codeRulePreconditionDOList = meterCodeRulePreconditionDAO.selectList(Wrappers.<MeterCodeRulePreconditionDO>lambdaQuery()
                .eq(MeterCodeRulePreconditionDO::getRuleId, id));
        // 根据规则id查询 设备编号规则字典
        List<MeterCodeRuleDictDO> codeRuleDictDOList = meterCodeRuleDictDAO.selectList(Wrappers.<MeterCodeRuleDictDO>lambdaQuery()
                .eq(MeterCodeRuleDictDO::getRuleId, id));

        return buildCodeRuleResponseDTO(codeRuleDO, codeRulePreconditionDOList, codeRuleDictDOList, dataParamTempDOList);
    }

    private CodeRuleResponseDTO getByIdGeneral(Long id) {
        // 根据id查询 设备编号规则
        CodeRuleDO codeRuleDO = codeRuleDAO.selectById(id);
        // 根据规则id查询 设备编号规则数据参量
        List<CodeRulePreconditionDO> codeRulePreconditionDOList = codeRulePreconditionDAO.selectList(Wrappers.<CodeRulePreconditionDO>lambdaQuery()
                .eq(CodeRulePreconditionDO::getRuleId, id));
        // 根据规则id查询 设备编号规则字典
        List<CodeRuleDictDO> codeRuleDictDOList = codeRuleDictDAO.selectList(Wrappers.<CodeRuleDictDO>lambdaQuery()
                .eq(CodeRuleDictDO::getRuleId, id));
        // 根据规则id查询 设备编号规则数据参量
        List<DataParamTempDO> dataParamTempDOList = dataParamTempDAO.selectList(Wrappers.<DataParamTempDO>lambdaQuery()
                .eq(DataParamTempDO::getRelationType, 1)
                .eq(DataParamTempDO::getRelationId, id));

        return buildCodeRuleResponseDTO(codeRuleDO, codeRulePreconditionDOList, codeRuleDictDOList, dataParamTempDOList);
    }

    /**
     * 删除 设备编号规则
     *
     * @param id 设备编号规则id
     * @return {@link Boolean}
     */
    @Override
    @Transactional(rollbackFor = ServerException.class)
    public Boolean delete(String type, Long id) throws ServiceException {
        Assert.notNull(type, "类型不能为空");

        if (CodeRuleTypeEnum.GENERAL.checkType(type)) {
            return deleteGeneral(id);
        } else {
            return deleteMeter(id);
        }
    }

    private Boolean deleteGeneral(Long id) {
        // 删除设备编号规则
        codeRuleDAO.deleteById(id);
        // 删除设备编号规则前置条件
        saveCodeRulePreconditionList(null, id, null);
        // 删除设备编号规则字典
        saveCodeRuleDictList(null, id);
        // 删除设备编号规则数据参量
        saveDataParamTempList(null, id, null);
        return Boolean.TRUE;
    }

    private Boolean deleteMeter(Long id) {
        // 删除设备编号规则
        meterCodeRuleDAO.deleteById(id);
        // 删除设备编号规则前置条件
        saveMeterCodeRulePreconditionList(null, id, null);
        // 删除设备编号规则字典
        saveMeterCodeRuleDictList(null, id);
        // 删除设备编号规则数据参量
        saveDataParamTempList(null, id, null);
        return Boolean.TRUE;
    }

    /**
     * 分页查询 设备编号规则
     *
     * @param levelId   级别标识
     * @param pageParam 页面参数
     * @return {@link PageData}<{@link CodeRuleResponseDTO}>
     */
    @Override
    public PageData<CodeRuleResponseDTO> page(String type, Long levelId, PageParam pageParam) throws ServiceException {
        Assert.notNull(type, "类型不能为空");

        if (CodeRuleTypeEnum.GENERAL.checkType(type)) {
            return pageGeneral(levelId, pageParam);
        } else {
            return pageMeter(levelId, pageParam);
        }
    }

    private PageData<CodeRuleResponseDTO> pageGeneral(Long levelId, PageParam pageParam) {
        // 封装查询条件QueryWrapper对象
        LambdaQueryWrapper<CodeRuleDO> wrapper = new LambdaQueryWrapper<CodeRuleDO>().eq(CodeRuleDO::getLevelId, levelId);

        // 分页查询统一用户信息信息
        Page<CodeRuleDO> page = Page
                .of(pageParam.getPageNo(), pageParam.getPageSize());
        PageData<CodeRuleDO> pageData = PageUtils
                .getPageData(codeRuleDAO.selectPage(page, wrapper), pageParam);
        return pageData.transformData(CodeRuleResponseDTO.class);
    }

    private PageData<CodeRuleResponseDTO> pageMeter(Long levelId, PageParam pageParam) {
        // 封装查询条件QueryWrapper对象
        LambdaQueryWrapper<MeterCodeRuleDO> wrapper = new LambdaQueryWrapper<MeterCodeRuleDO>().eq(MeterCodeRuleDO::getLevelId, levelId);

        // 分页查询统一用户信息信息
        Page<MeterCodeRuleDO> page = Page
                .of(pageParam.getPageNo(), pageParam.getPageSize());
        PageData<MeterCodeRuleDO> pageData = PageUtils
                .getPageData(meterCodeRuleDAO.selectPage(page, wrapper), pageParam);
        return pageData.transformData(CodeRuleResponseDTO.class);
    }


    /**
     * 按名称获取字典规则
     *
     * @param name 名字
     * @return {@link CodeRuleDictDTO}
     */
    @Override
    public CodeRuleDictDTO getDictRuleByName(String type, String name) {
        CodeRuleDictDTO codeRuleDictDTO = new CodeRuleDictDTO();
        String[] split = name.split("#");
        String levelName = split[0];
        String dictName = split[1];
        if (CodeRuleTypeEnum.GENERAL.getType().equals(type)){
            List<CodeRuleDictDO> codeRuleDictDOList = codeRuleDictDAO
                    .selectList(Wrappers.<CodeRuleDictDO>lambdaQuery()
                            .eq(CodeRuleDictDO::getDescription, dictName));
            if (CollUtil.isEmpty(codeRuleDictDOList)) {
                return codeRuleDictDTO;
            }
            if (codeRuleDictDOList.size() == 1) {
                BeanUtils.copyObject(codeRuleDictDOList.get(0), codeRuleDictDTO);
            }

            CodeLevelDO codeLevelDO = codeLevelDAO.selectOne(Wrappers.<CodeLevelDO>lambdaQuery()
                    .eq(CodeLevelDO::getName, levelName).last("limit 1"));
            if (ObjectUtils.isEmpty(codeLevelDO)) {
                return codeRuleDictDTO;
            }
            Long levelId = codeLevelDO.getId();
            CodeRuleDictSelectQueryDTO queryDTO = new CodeRuleDictSelectQueryDTO(levelId, null);
            List<CodeRuleDictDTO> codeRuleDictList = listRuleDictSelect(type, queryDTO);

            for (CodeRuleDictDTO ruleDictDTO : codeRuleDictList) {
                if (ruleDictDTO.getDescription().equals(dictName)) {
                    BeanUtils.copyObject(ruleDictDTO, codeRuleDictDTO);
                }
            }
        }
        if (CodeRuleTypeEnum.METER.getType().equals(type)){
            List<MeterCodeRuleDictDO> meterCodeRuleDictDOList = meterCodeRuleDictDAO
                    .selectList(Wrappers.<MeterCodeRuleDictDO>lambdaQuery()
                            .eq(MeterCodeRuleDictDO::getDescription, dictName));
            if (CollUtil.isEmpty(meterCodeRuleDictDOList)) {
                return codeRuleDictDTO;
            }
            if (meterCodeRuleDictDOList.size() == 1) {
                return BeanUtils.copyToObject(meterCodeRuleDictDOList.get(0), CodeRuleDictDTO.class);
            }

            MeterCodeLevelDO meterCodeLevelDO = meterCodeLevelDAO.selectOne(Wrappers.<MeterCodeLevelDO>lambdaQuery()
                    .eq(MeterCodeLevelDO::getName, levelName).last("limit 1"));
            if (ObjectUtils.isEmpty(meterCodeLevelDO)) {
                return codeRuleDictDTO;
            }
            Long levelId = meterCodeLevelDO.getId();
            CodeRuleDictSelectQueryDTO queryDTO = new CodeRuleDictSelectQueryDTO(levelId, null);
            List<CodeRuleDictDTO> codeRuleDictList = listRuleDictSelect(type, queryDTO);

            for (CodeRuleDictDTO ruleDictDTO : codeRuleDictList) {
                if (ruleDictDTO.getDescription().equals(dictName)) {
                    BeanUtils.copyObject(ruleDictDTO, codeRuleDictDTO);
                }
            }
        }
        return codeRuleDictDTO;
    }

    /**
     * 按名称映射 Dict 规则
     *
     * @param type     类型
     * @param nameList 名称列表
     * @return {@link Map}<{@link String}, {@link CodeRuleDictDTO}>
     * @throws ServiceException 服务异常
     */
    @Override
    public Map<String, CodeRuleDictDTO> mapDictRuleByName(String type, List<String> nameList)
            throws ServiceException {
        Map<String, CodeRuleDictDTO> map = new HashMap<>();
        List<String> collect = nameList.stream().distinct().collect(Collectors.toList());
        collect.forEach(name -> {
            map.put(name, getDictRuleByName(type, name));
        });
        return map;
    }

    /**
     * 按名称列表 获取字典规则
     *
     * @param type                 类型
     * @param codeRuleDictNameList 代码规则字典名称列表
     * @return {@link Map}<{@link String}, {@link CodeRuleDictDTO}>
     * @throws ServiceException 服务异常
     */
    @Override
    public Map<String, CodeRuleDictDTO> mapRuleDictNameByNameList(String type, List<String> codeRuleDictNameList)
            throws ServiceException {
        List<CodeRuleDictDTO> codeRuleDictDTOList = new ArrayList<>();
        codeRuleDictNameList.forEach(name -> {
            codeRuleDictDTOList.add(getDictRuleByName(type, name));
        });
        return codeRuleDictDTOList.stream().collect(Collectors.toMap(CodeRuleDictDTO::getDescription, codeRuleDictDTO -> codeRuleDictDTO));
    }


    /**
     * 列表规则字典选择
     *
     * @param codeRuleDictSelectQueryDTO 设备编码规则字典选择查询 DTO
     * @return {@link List}<{@link CodeRuleDictDTO}> 设备编码规则字典选择列表
     */
    @Override
    public List<CodeRuleDictDTO> listRuleDictSelect(String type, CodeRuleDictSelectQueryDTO codeRuleDictSelectQueryDTO) throws ServiceException {
        Assert.notNull(type, "类型不能为空");
        if (CodeRuleTypeEnum.GENERAL.checkType(type)) {
            return listRuleDictSelectGeneral(codeRuleDictSelectQueryDTO);
        } else {
            return listRuleDictSelectMeter(codeRuleDictSelectQueryDTO);
        }
    }

    private List<CodeRuleDictDTO> listRuleDictSelectMeter(CodeRuleDictSelectQueryDTO codeRuleDictSelectQueryDTO) {
        Long targetLevelId = codeRuleDictSelectQueryDTO.getTargetLevelId();
        List<CodeRuleDictQueryDTO> codeRuleDictQueryList = codeRuleDictSelectQueryDTO.getCodeRuleDictQueryList();
        List<Long> ruleIdList = new ArrayList<>();

        // 目标级别ID为空，直接返回空列表
        if (codeRuleDictQueryList == null) {
            ruleIdList = meterCodeRulePreconditionDAO.listRuleIdByTargetLevelId(targetLevelId);
        } else if (codeRuleDictQueryList.size() == 0) {
            ruleIdList = meterCodeRulePreconditionDAO.listRuleIdByTargetLevelIdAndDictIds(targetLevelId);
        } else {
            // 根据目标级别ID和字典查询列表查询规则ID列表
            for (CodeRuleDictQueryDTO codeRuleDictQuery : codeRuleDictQueryList) {
                List<Long> temp = meterCodeRulePreconditionDAO.listRuleIdByTargetLevelIdAndDictQuery(targetLevelId, BeanUtils.copyToObject(codeRuleDictQuery, CodeRuleDictQueryVO.class));
                if (CollUtil.isEmpty(ruleIdList)) {
                    ruleIdList = temp;
                } else {
                    ruleIdList.retainAll(temp);
                }
            }
        }

        // 清洗处理的规则ID列表
        List<Long> cleanRuleIdList = ruleIdList.stream().distinct().collect(Collectors.toList());
        if (CollUtil.isEmpty(cleanRuleIdList)) {
            return CollUtil.newArrayList();
        }

        List<MeterCodeRuleDictDO> codeRuleDictList = meterCodeRuleDictDAO.selectList(new LambdaQueryWrapper<MeterCodeRuleDictDO>()
                .in(MeterCodeRuleDictDO::getRuleId, cleanRuleIdList)
                .orderByAsc(MeterCodeRuleDictDO::getSortNumber));
        return BeanUtils.copyToList(codeRuleDictList, CodeRuleDictDTO.class);
    }

    private List<CodeRuleDictDTO> listRuleDictSelectGeneral(CodeRuleDictSelectQueryDTO codeRuleDictSelectQueryDTO) {
        Long targetLevelId = codeRuleDictSelectQueryDTO.getTargetLevelId();
        List<CodeRuleDictQueryDTO> codeRuleDictQueryList = codeRuleDictSelectQueryDTO.getCodeRuleDictQueryList();
        List<Long> ruleIdList = new ArrayList<>();

        // 目标级别ID为空，直接返回空列表
        if (codeRuleDictQueryList == null) {
            ruleIdList = codeRulePreconditionDAO.listRuleIdByTargetLevelId(targetLevelId);
        } else if (codeRuleDictQueryList.size() == 0) {
            ruleIdList = codeRulePreconditionDAO.listRuleIdByTargetLevelIdAndDictIds(targetLevelId);
        } else {
            // 根据目标级别ID和字典查询列表查询规则ID列表
            for (CodeRuleDictQueryDTO codeRuleDictQuery : codeRuleDictQueryList) {
                List<Long> temp = codeRulePreconditionDAO.listRuleIdByTargetLevelIdAndDictQuery(targetLevelId, BeanUtils.copyToObject(codeRuleDictQuery, CodeRuleDictQueryVO.class));
                if (CollUtil.isEmpty(ruleIdList)) {
                    ruleIdList = temp;
                } else {
                    ruleIdList.retainAll(temp);
                }
            }
        }

        // 清洗处理的规则ID列表
        List<Long> cleanRuleIdList = ruleIdList.stream().distinct().collect(Collectors.toList());
        if (CollUtil.isEmpty(cleanRuleIdList)) {
            return CollUtil.newArrayList();
        }

        List<CodeRuleDictDO> codeRuleDictList = codeRuleDictDAO.selectList(new LambdaQueryWrapper<CodeRuleDictDO>()
                .in(CodeRuleDictDO::getRuleId, cleanRuleIdList)
                .orderByAsc(CodeRuleDictDO::getSortNumber));
        return BeanUtils.copyToList(codeRuleDictList, CodeRuleDictDTO.class);
    }

    /**
     * 生成设备编号
     *
     * @param codeRuleDictList 设备编号规则字典id集合 可以包含 随机数 （%+位数）或 顺序数（#+位数）
     * @return {@link String}
     */
    @Override
    @Transactional(rollbackFor = ServerException.class)
    public String getCodeByCodeRuleId(String type, List<String> codeRuleDictList) throws ServiceException {
        Assert.notNull(type, "类型不能为空");
        if (CodeRuleTypeEnum.GENERAL.checkType(type)) {
            return getCodeByCodeRuleIdGeneral(codeRuleDictList);
        } else {
            return getCodeByCodeRuleIdMeter(codeRuleDictList);
        }
    }

    private String getCodeByCodeRuleIdGeneral(List<String> codeRuleDictList) {
        StringBuilder code = new StringBuilder();
        String tempStr = "";
        for (String dictId : codeRuleDictList) {
            if (dictId.startsWith("%") || dictId.startsWith("#")) {
                if (dictId.startsWith("%")) {
                    // 随机数
                    int i = Integer.parseInt(dictId.replace("%", ""));
                    code.append(StrUtils.getRandomString(i));
                } else if (dictId.startsWith("#")) {
                    // 顺序数
                    tempStr = dictId;
                    code.append(dictId);
                }
            } else {
                CodeRuleDictDO codeRuleDictDO = codeRuleDictDAO.selectById(Long.parseLong(dictId));
                Assert.notNull(codeRuleDictDO, "字典不存在");
                code.append(codeRuleDictDO.getValue()).append(StrUtil.C_UNDERLINE);
            }
            if (StringUtils.isNoneBlank(tempStr)) {
                String ruleDictValues = code.toString();

                CodeRuleSerialNumberDO codeRuleSerialNumberDO = codeRuleSerialNumberDAO
                        .selectOne(new LambdaQueryWrapper<CodeRuleSerialNumberDO>()
                                .eq(CodeRuleSerialNumberDO::getRuleDictValues, ruleDictValues));

                if (codeRuleSerialNumberDO != null) {
                    codeRuleSerialNumberDO.setCount(codeRuleSerialNumberDO.getCount() + 1);
                    codeRuleSerialNumberDAO.updateById(codeRuleSerialNumberDO);
                } else {
                    codeRuleSerialNumberDO = new CodeRuleSerialNumberDO();
                    codeRuleSerialNumberDO.setRuleDictValues(ruleDictValues);
                    codeRuleSerialNumberDO.setCount(1);
                    codeRuleSerialNumberDAO.insert(codeRuleSerialNumberDO);
                }

                int i = Integer.parseInt(dictId.replace("#", ""));
                String format = String.format("%0" + i + "d", codeRuleSerialNumberDO.getCount());
                code = new StringBuilder(code.toString().replace(tempStr, format));
            }
        }
        return code.toString();
    }

    private String getCodeByCodeRuleIdMeter(List<String> codeRuleDictList) {
        StringBuilder code = new StringBuilder();
        String tempStr = "";
        for (String dictId : codeRuleDictList) {
            if (dictId.startsWith("%") || dictId.startsWith("#")) {
                if (dictId.startsWith("%")) {
                    // 随机数
                    int i = Integer.parseInt(dictId.replace("%", ""));
                    code.append(StrUtils.getRandomString(i));
                } else if (dictId.startsWith("#")) {
                    // 顺序数
                    tempStr = dictId;
                    code.append(dictId);
                }
            } else {
                MeterCodeRuleDictDO codeRuleDictDO = meterCodeRuleDictDAO.selectById(Long.parseLong(dictId));
                Assert.notNull(codeRuleDictDO, "字典不存在");
                code.append(codeRuleDictDO.getValue()).append(StrUtil.C_UNDERLINE);
            }
            if (StringUtils.isNoneBlank(tempStr)) {
                String ruleDictValues = code.toString();

                MeterCodeRuleSerialNumberDO codeRuleSerialNumberDO = meterCodeRuleSerialNumberDAO
                        .selectOne(new LambdaQueryWrapper<MeterCodeRuleSerialNumberDO>()
                                .eq(MeterCodeRuleSerialNumberDO::getRuleDictValues, ruleDictValues));

                if (codeRuleSerialNumberDO != null) {
                    codeRuleSerialNumberDO.setCount(codeRuleSerialNumberDO.getCount() + 1);
                    meterCodeRuleSerialNumberDAO.updateById(codeRuleSerialNumberDO);
                } else {
                    codeRuleSerialNumberDO = new MeterCodeRuleSerialNumberDO();
                    codeRuleSerialNumberDO.setRuleDictValues(ruleDictValues);
                    codeRuleSerialNumberDO.setCount(1);
                    meterCodeRuleSerialNumberDAO.insert(codeRuleSerialNumberDO);
                }

                int i = Integer.parseInt(dictId.replace("#", ""));
                String format = String.format("%0" + i + "d", codeRuleSerialNumberDO.getCount());
                code = new StringBuilder(code.toString().replace(tempStr, format));
            }
        }
        return code.toString();
    }

    private DataParamTempServiceImpl dataParamTempService;

    /**
     * 保存数据参数临时列表
     *
     * @param dataParamTempList 数据参数临时列表
     * @param ruleId            规则标识
     */
    private void saveDataParamTempList(List<DataParamTempDTO> dataParamTempList, Long ruleId, Integer type) {
        // 清理原有的数据参量数据
        dataParamTempDAO.delete(Wrappers.<DataParamTempDO>lambdaQuery()
                .eq(DataParamTempDO::getRelationType, type)
                .eq(DataParamTempDO::getRelationId, ruleId));
        dataParamTempService.saveBatch(BeanUtils.copyToList(dataParamTempList, DataParamTempVO.class), ruleId, type);
    }

    /**
     * 保存代码规则字典列表
     *
     * @param codeRuleDictDTOList 代码规则字典 dtolist
     * @param ruleId              规则标识
     */
    private void saveCodeRuleDictList(List<CodeRuleDictDTO> codeRuleDictDTOList, Long ruleId) {
        if (CollUtil.isEmpty(codeRuleDictDTOList)) {
            codeRuleDictDAO.delete(Wrappers.<CodeRuleDictDO>lambdaQuery().eq(CodeRuleDictDO::getRuleId, ruleId));
            return;
        }
        // 走增量更新 考虑后续字典项关联的东西太多，不直接删除
        List<CodeRuleDictDO> oldCodeRuleDictList = codeRuleDictDAO.selectList(Wrappers.<CodeRuleDictDO>lambdaQuery()
                .eq(CodeRuleDictDO::getRuleId, ruleId));

        // 要新增的数据
        List<CodeRuleDictDTO> toSaveList = codeRuleDictDTOList.stream()
                .filter(dto -> ObjectUtils.isEmpty(dto.getId()))
                .collect(Collectors.toList());

        toSaveBatch(toSaveList, ruleId);

        // 要更新的数据
        List<CodeRuleDictDTO> toUpdateList = codeRuleDictDTOList.stream()
                .filter(dto -> ObjectUtils.isNotEmpty(dto.getId()))
                .collect(Collectors.toList());

        toUpdateBatch(toUpdateList, ruleId);

        if (CollUtil.isNotEmpty(oldCodeRuleDictList)) {
            // 要删除的数据
            List<CodeRuleDictDO> toDeleteList = oldCodeRuleDictList.stream()
                    .filter(dto -> toUpdateList.stream().noneMatch(dto2 -> dto2.getId().equals(dto.getId())))
                    .collect(Collectors.toList());
            toDeleteBatch(toDeleteList);
        }

    }

    private void toSaveBatch(List<CodeRuleDictDTO> toSaveList, Long ruleId) {
        if (CollectionUtil.isNotEmpty(toSaveList)) {
            List<CodeRuleDictDO> collect = toSaveList.stream().map(codeRuleDictDTO -> {
                CodeRuleDictDO codeRuleDictDO = BeanUtils.copyToObject(codeRuleDictDTO, CodeRuleDictDO.class);
                codeRuleDictDO.setId(null);
                codeRuleDictDO.setRuleId(ruleId);
                return codeRuleDictDO;
            }).collect(Collectors.toList());
            codeRuleDictDAO.insertBatch(collect);
        }
    }

    private void toUpdateBatch(List<CodeRuleDictDTO> toUpdateList, Long ruleId) {
        if (CollectionUtil.isNotEmpty(toUpdateList)) {
            List<CodeRuleDictDO> collect = toUpdateList.stream().map(codeRuleDictDTO -> {
                CodeRuleDictDO codeRuleDictDO = BeanUtils.copyToObject(codeRuleDictDTO, CodeRuleDictDO.class);
                codeRuleDictDO.setRuleId(ruleId);
                return codeRuleDictDO;
            }).collect(Collectors.toList());
            codeRuleDictDAO.updateBatch(collect);
        }
    }

    private void toDeleteBatch(List<CodeRuleDictDO> toDeleteList) {
        if (CollectionUtil.isNotEmpty(toDeleteList)) {
            List<Long> ids = toDeleteList.stream().map(CodeRuleDictDO::getId).collect(Collectors.toList());
            codeRuleDictDAO.deleteBatchIds(ids);

            ids.forEach(id -> {
                codeRulePreconditionDAO.delete(Wrappers.<CodeRulePreconditionDO>lambdaQuery()
                        .like(CodeRulePreconditionDO::getRuleDictIds, StrUtil.C_COMMA + id + StrUtil.C_COMMA));
            });
        }
    }

    /**
     * 保存代码规则字典列表
     *
     * @param codeRuleDictList 代码规则字典 dtolist
     * @param ruleId           规则标识
     */
    private void saveMeterCodeRuleDictList(List<CodeRuleDictDTO> codeRuleDictList, Long ruleId) {
        // 清理原有的字典数据
        meterCodeRuleDictDAO.delete(Wrappers.<MeterCodeRuleDictDO>lambdaQuery().eq(MeterCodeRuleDictDO::getRuleId, ruleId));
        // 重新保存
        if (CollectionUtil.isNotEmpty(codeRuleDictList)) {
            List<MeterCodeRuleDictDO> collect = codeRuleDictList.stream().map(codeRuleDictDTO -> {
                MeterCodeRuleDictDO codeRuleDictDO = BeanUtils.copyToObject(codeRuleDictDTO, MeterCodeRuleDictDO.class);
                codeRuleDictDO.setId(null);
                codeRuleDictDO.setRuleId(ruleId);
                return codeRuleDictDO;
            }).collect(Collectors.toList());
            meterCodeRuleDictDAO.insertBatch(collect);
        }
    }

    /**
     * 保存代码规则前提条件列表
     *
     * @param codeRulePreconditionList 代码规则前提条件列表
     * @param ruleId                   规则标识
     */
    private void saveCodeRulePreconditionList(List<CodeRulePreconditionDTO> codeRulePreconditionList, Long ruleId, Long levelId) {
        // 清理原有的字典数据
        codeRulePreconditionDAO.delete(Wrappers.<CodeRulePreconditionDO>lambdaQuery().eq(CodeRulePreconditionDO::getRuleId, ruleId));
        // 重新保存
        if (CollectionUtil.isNotEmpty(codeRulePreconditionList)) {
            codeRulePreconditionList.forEach(codeRulePreconditionDTO -> {
                CodeRulePreconditionDO codeRulePreconditionDO =
                        BeanUtils.copyToObject(codeRulePreconditionDTO, CodeRulePreconditionDO.class);
                codeRulePreconditionDO.setId(null);
                codeRulePreconditionDO.setRuleId(ruleId);
                codeRulePreconditionDO.setTargetLevelId(levelId);
                // 特殊处理 rule_dict_ids 字段 起始末尾加上逗号 方便查询使用
                if (StrUtil.isNotBlank(codeRulePreconditionDO.getRuleDictIds())) {
                    codeRulePreconditionDO.setRuleDictIds(StrUtil.C_COMMA + codeRulePreconditionDO.getRuleDictIds() + StrUtil.C_COMMA);
                }
                codeRulePreconditionDAO.insert(codeRulePreconditionDO);
            });
        } else {
            if (levelId != null) {
                // 保存前置规则条件关联关系
                CodeRulePreconditionDO codeRulePreconditionDO = new CodeRulePreconditionDO();
                codeRulePreconditionDO.setId(null);
                codeRulePreconditionDO.setRuleId(ruleId);
                codeRulePreconditionDO.setTargetLevelId(levelId);
                codeRulePreconditionDAO.insert(codeRulePreconditionDO);
            }
        }
    }

    /**
     * 保存代码规则前提条件列表
     *
     * @param codeRulePreconditionList 代码规则前提条件列表
     * @param ruleId                   规则标识
     */
    private void saveMeterCodeRulePreconditionList(List<CodeRulePreconditionDTO> codeRulePreconditionList, Long ruleId, Long levelId) {
        // 清理原有的字典数据
        meterCodeRulePreconditionDAO.delete(Wrappers.<MeterCodeRulePreconditionDO>lambdaQuery().eq(MeterCodeRulePreconditionDO::getRuleId, ruleId));
        // 重新保存
        if (CollectionUtil.isNotEmpty(codeRulePreconditionList)) {
            codeRulePreconditionList.forEach(codeRulePreconditionDTO -> {
                MeterCodeRulePreconditionDO codeRulePreconditionDO =
                        BeanUtils.copyToObject(codeRulePreconditionDTO, MeterCodeRulePreconditionDO.class);
                codeRulePreconditionDO.setId(null);
                codeRulePreconditionDO.setRuleId(ruleId);
                codeRulePreconditionDO.setTargetLevelId(levelId);
                // 特殊处理 rule_dict_ids 字段 起始末尾加上逗号 方便查询使用
                if (StrUtil.isNotBlank(codeRulePreconditionDO.getRuleDictIds())) {
                    codeRulePreconditionDO.setRuleDictIds(StrUtil.C_COMMA + codeRulePreconditionDO.getRuleDictIds() + StrUtil.C_COMMA);
                }
                meterCodeRulePreconditionDAO.insert(codeRulePreconditionDO);
            });
        } else {
            if (levelId != null) {
                // 保存前置规则条件关联关系
                MeterCodeRulePreconditionDO codeRulePreconditionDO = new MeterCodeRulePreconditionDO();
                codeRulePreconditionDO.setId(null);
                codeRulePreconditionDO.setRuleId(ruleId);
                codeRulePreconditionDO.setTargetLevelId(levelId);
                meterCodeRulePreconditionDAO.insert(codeRulePreconditionDO);
            }
        }
    }


    /**
     * 构建 设备编号规则返回DTO对象
     *
     * @param codeRuleDO                 设备编号规则DO对象
     * @param codeRulePreconditionDOList 设备编号规则前置条件DO列表
     * @param codeRuleDictDOList         设备编号规则字典DO列表
     * @param dataParamTempDOList        设备编号规则数据参量DO列表
     * @return {@link CodeRuleResponseDTO}
     */
    private CodeRuleResponseDTO buildCodeRuleResponseDTO(CodeRuleDO codeRuleDO,
                                                         List<CodeRulePreconditionDO> codeRulePreconditionDOList,
                                                         List<CodeRuleDictDO> codeRuleDictDOList,
                                                         List<DataParamTempDO> dataParamTempDOList) {
        CodeRuleResponseDTO codeRuleResponseDTO = new CodeRuleResponseDTO();
        // 设备编号规则DO对象转换为DTO对象
        BeanUtils.copyObject(codeRuleDO, codeRuleResponseDTO);
        // 设备编号规则前置条件DO列表转换为DTO列表
        List<CodeRulePreconditionDTO> codeRulePreconditionList = BeanUtils
                .copyToList(codeRulePreconditionDOList, CodeRulePreconditionDTO.class);
        codeRuleResponseDTO.setCodeRulePreconditionList(codeRulePreconditionList);
        // 设备编号规则字典DO列表转换为DTO列表
        codeRuleResponseDTO.setCodeRuleDictList(BeanUtils.copyToList(codeRuleDictDOList, CodeRuleDictDTO.class));
        // 设备编号规则数据参量DO列表转换为DTO列表
        codeRuleResponseDTO.setDataParamTempList(BeanUtils.copyToList(dataParamTempDOList, DataParamTempDTO.class));
        return codeRuleResponseDTO;
    }

    private CodeRuleResponseDTO buildCodeRuleResponseDTO(MeterCodeRuleDO codeRuleDO,
                                                         List<MeterCodeRulePreconditionDO> codeRulePreconditionDOList,
                                                         List<MeterCodeRuleDictDO> codeRuleDictDOList,
                                                         List<DataParamTempDO> dataParamTempDOList) {
        CodeRuleResponseDTO codeRuleResponseDTO = new CodeRuleResponseDTO();
        // 设备编号规则DO对象转换为DTO对象
        BeanUtils.copyObject(codeRuleDO, codeRuleResponseDTO);
        // 设备编号规则前置条件DO列表转换为DTO列表
        List<CodeRulePreconditionDTO> codeRulePreconditionList = BeanUtils
                .copyToList(codeRulePreconditionDOList, CodeRulePreconditionDTO.class);
        codeRuleResponseDTO.setCodeRulePreconditionList(codeRulePreconditionList);
        // 设备编号规则字典DO列表转换为DTO列表
        codeRuleResponseDTO.setCodeRuleDictList(BeanUtils.copyToList(codeRuleDictDOList, CodeRuleDictDTO.class));
        // 设备编号规则数据参量DO列表转换为DTO列表
        codeRuleResponseDTO.setDataParamTempList(BeanUtils.copyToList(dataParamTempDOList, DataParamTempDTO.class));
        return codeRuleResponseDTO;
    }

}
